package com.payment.common.utils;

import com.payment.common.utils.pay.EncryptUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.TreeMap;

/**
 * 签名工具类
 *
 * @author tinn
 *
 */
public class SignUtil {
    private static final Logger log = LoggerFactory.getLogger(SignUtil.class);

    /**
     * 比较签名是否正确
     *
     * @param origSign
     * @return
     */
    public static boolean signVerifyByObject(String channelKey, String origSign, Object... signObjs) {
        if (origSign == null) {
            return false;
        }
        String newSign = signByObject(channelKey, signObjs);
        if (origSign.equalsIgnoreCase(newSign)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 生成签名
     *
     * @param signObjs
     *            签名所需元素
     * @return
     */
    public static String signByObject(String channelKey, Object... signObjs) {
        // 计算签名所需要的内容
        StringBuilder signContent = new StringBuilder();
        signContent.append(channelKey);
        // 有参数的情况下，签名内容需要拼接参数
        if (signObjs != null && signObjs.length > 0) {
            for (Object signElement : signObjs) {
                if (signElement != null) {
                    signContent.append(signElement);
                }
            }
        }

        log.info("签名工具类-生成签名="+signContent.toString());

        // 生成签名
        String sign = EncryptUtil.md5Encrypt(signContent.toString());
        return sign;
    }

    /**
     * 签名
     *
     * @param map
     * @return
     */
    public static String signByMap(String channelKey, TreeMap<String, Object> map) {
        log.info("sign start");
        try {
            StringBuilder sb = new StringBuilder();
            Iterator<String> iterator = map.keySet().iterator();
            sb.append(channelKey);
            while (iterator.hasNext()) {
                Object key = iterator.next();
                Object valueObj = map.get(key);
                if (valueObj != null) {
                    // 并将获取的值进行拼接
                    String value = valueObj.toString();
                    log.info("map:" + key + ":" + value);
                    sb.append(value);
                }
            }
            log.info("SignData orig Data : " + sb.toString());
            String signData = EncryptUtil.md5Encrypt(sb.toString());
            log.info("SignData : " + signData);
            return signData;
        } catch (Exception e) {
            log.error("签名工具类-签名异常="+e.toString());
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 按照签名规则生成验签字符串
     * 第一步：对参数按照key=value的格式，并按照参数名ASCII字典序排序如下
     * stringA="param1=value1&param2=value2&param3=value3&param4=value4&param5=value5";
     *
     * @param sortMap
     * @return
     */
    public static String createSignA(TreeMap<String, Object> sortMap) {
        StringBuffer sb = new StringBuffer();
        if (sortMap == null || sortMap.isEmpty()) {
            return "";
        }
        for (Object key : sortMap.keySet()) {
            // value为空或为null 不参与签名
            if (StringUtils.isNotBlank((String) sortMap.get(key))) {
                // sign 不参与签名
                if (!"sign".equals(key)) {
                    sb.append(key + "=" + sortMap.get(key) + "&");
                }
            }

        }
        return sb.substring(0, sb.length() - 1);
    }

    /**
     * 第二步 在stringA最后拼接上key得到stringSignTemp字符串
     * 并对stringSignTemp进行MD5运算，再将得到的字符串所有字符转换为大写，得到sign值signValue
     *
     * @param key
     * @return
     */
    public static String sign(TreeMap <String, Object> map, String key) {
        try {
            String stringSignTemp = createSignA(map) + "&key=" + key;
            return Md5Utils.encrypt2MD5(stringSignTemp).toUpperCase();
        } catch (Exception e) {
            log.error("sortedMap createSign error: {}", e);
            return "";
        }
    }
    /**
     * 验证签名
     *
     * @param map
     * @param sign
     * @return
     */
    public static boolean signVerifyByMap(String channelKey, TreeMap<String, Object> map, String sign) {
        log.info("verify sign start ! sign :" + sign);
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(channelKey);
            Iterator<String> iterator = map.keySet().iterator();
            while (iterator.hasNext()) {
                Object key = iterator.next();
                // 并将获取的值进行拼接
                Object valueObj = map.get(key);
                if (valueObj != null) {
                    String value = valueObj.toString();
                    log.info("map:" + key + ":" + value);
                    sb.append(value);
                }
            }
            String md5Result = EncryptUtil.md5Encrypt(sb.toString());
            if (sign.equalsIgnoreCase(md5Result)) {
                log.info("verify success");
                return true;
            } else {
                log.info("verify failure");
                return false;
            }
        } catch (Exception e) {
            log.error("验证签名异常"+e.toString());
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 转化为TreeMap
     * @param request
     * @return
     */
    public static TreeMap <String, Object> getParameterMap(final ServletRequest request) {
        final TreeMap <String, Object> map;
        if (request == null) {
            return null;
        } else {
            map = new TreeMap <String, Object>();
            final Enumeration<String> parameterNames = request.getParameterNames();
            while (parameterNames.hasMoreElements()) {
                final String parameterName = parameterNames.nextElement();
                map.put(parameterName, request.getParameter(parameterName));
            }
        }
        return map;
    }

}
